package com.dy.lock.screen.scoket;

import java.io.IOException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.apache.log4j.Logger;
import org.apache.mina.core.filterchain.IoFilter;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.executor.ExecutorFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.dy.lock.screen.constants.TransmissionCode;
import com.dy.lock.screen.exception.ServerDisponseException;
import com.dy.lock.screen.parse.BeanVO;
import com.dy.lock.screen.parse.Parser;
import com.dy.lock.screen.server.StartMain;
import com.dy.lock.screen.utils.CommonUtil;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

@Service
public class Server {
	@Value("${socket.server.port}")
	private int port;
	private static final Logger log = Logger.getLogger(Server.class);

	/**
	 * 启动socket服务器
	 */
	@PostConstruct
	public void start() throws IOException {
		IoAcceptor acceptor = new NioSocketAcceptor();
		TextLineCodecFactory lineCodec = new TextLineCodecFactory(Charset
				.forName("UTF-8"));
		lineCodec.setDecoderMaxLineLength(1024 * 500); // 200k
		lineCodec.setEncoderMaxLineLength(1024 * 500);
		IoFilter filter = new ProtocolCodecFilter(lineCodec);
		IoFilter checkedFilter = new TransmissionMessageCheckFilter();
		acceptor.getFilterChain().addLast("code", filter);
		acceptor.getFilterChain().addLast("checkedFilter", checkedFilter);
		acceptor.getFilterChain().addLast("ExecutorFilter",
				new ExecutorFilter(300));
		acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 4);
		acceptor.getSessionConfig().setWriteTimeout(4);
		acceptor.getSessionConfig().setReaderIdleTime(2);
		acceptor.getSessionConfig().setReadBufferSize(1024);
		acceptor.setHandler(new ServerHandler());
		acceptor.bind(new InetSocketAddress(port));
		log.info("系统启动，开放端口:" + port);
	}

	private class ServerHandler extends IoHandlerAdapter {

		/**
		 * socket请求处理方法
		 */
		@Override
		public void messageReceived(IoSession session, Object message)
				throws Exception {
			Gson gson = CommonUtil.gson();
			SocketDTO socketDTO = new SocketDTO();
			Map<String, BeanVO> map = new Parser().getParserMap();
			JsonParser parser = new JsonParser();
			JsonObject o = parser.parse(message.toString()).getAsJsonObject();
			JsonElement headStr = o.get("head");
			JsonElement body = o.get("body");
			if (body != null) {
				socketDTO.setBody(body.toString());
			}
			socketDTO.setHead(gson.fromJson(headStr, Head.class));
			Head head = socketDTO.getHead();
			head.setResponseCode(null);
			head.setResponseMessage(null);
			if (log.isInfoEnabled())
				log.info(head.getRequestId() + "请求包:[" + message + "]");
			BeanVO beanVO = map.get(head.getServiceCode());
			Object bean = null;
			if (beanVO != null)
				bean = StartMain.APPLICATION_CONTEXT.getBean(beanVO.getId());
			Object result = null;
			if (beanVO != null && bean != null) {
				for (Method method : bean.getClass().getMethods()) {
					if (method.getName().equals(beanVO.getMethod())) {
						if (method.getName().equals(beanVO.getMethod())) {
							Class<?>[] paraType = method.getParameterTypes();
							Object[] pars = new Object[method
									.getParameterTypes().length];
							int r = 0;
							for (Class<?> object : paraType) {
								if (r == 0
										&& socketDTO.getBody() != null
										&& object.getName().equals(
												socketDTO.getBody().getClass()
														.getName()))
									pars[r] = socketDTO.getBody();
								else if (object.getName().equals(
										Head.class.getName()))
									pars[r] = head.clone();
								r++;
							}
							try {
								result = method.invoke(bean, pars);
							} catch (Exception t) {
								if (t.getCause() instanceof ServerDisponseException) {
									ServerDisponseException dis = (ServerDisponseException) t
											.getCause();
									head.setResponseCode(dis.getCode());
									head.setResponseMessage(dis.getMessage());
								} else {
									if (t.getCause() instanceof DuplicateKeyException) {
										head
												.setResponseCode(TransmissionCode.DUPLICATE_KEY_ERROR
														.getCode());
										head
												.setResponseMessage(TransmissionCode.DUPLICATE_KEY_ERROR
														.getMessage());
										log
												.info(
														TransmissionCode.DUPLICATE_KEY_ERROR
																.getMessage(),
														t);
									} else {
										head
												.setResponseCode(TransmissionCode.ERROR
														.getCode());
										head
												.setResponseMessage(TransmissionCode.ERROR
														.getMessage());
										log.error(TransmissionCode.ERROR
												.getMessage(), t);
									}
								}
							} finally {
								
							}
							break;
						}
					}
				}
				if (!StringUtils.hasText(head.getResponseCode())) {
					head.setResponseCode(TransmissionCode.SUCCESS.getCode());
					head.setResponseMessage(TransmissionCode.SUCCESS
							.getMessage());
				}
			} else {
				head.setResponseCode(TransmissionCode.SERVICE_NO_FOUND
						.getCode());
				head.setResponseMessage(TransmissionCode.SERVICE_NO_FOUND
						.getMessage());
			}
			socketDTO = new SocketDTO();
			socketDTO.setHead(head);
			String resultMessage = gson.toJson(socketDTO);
			o = parser.parse(resultMessage).getAsJsonObject();
			if (result != null) {
				boolean type = false;
				try {
					if ((result instanceof String)
							&& (parser.parse(result.toString()).isJsonObject() || parser
									.parse(result.toString()).isJsonArray())) {
						type = true;
					}
				} catch (Exception e) {
				}
				if (type)
					o.add("body", parser.parse(result.toString()));
				else
					o.add("body", parser.parse(gson.toJson(result)));
				resultMessage = o.toString();
			}
			if (log.isInfoEnabled())
				log.info(head.getRequestId() + "响应包:[" + resultMessage + "]");
			session.write(resultMessage);
			session.close(false);
		}

		@Override
		public void sessionClosed(IoSession session) throws Exception {
			session.close(true);
		}

		@Override
		public void sessionIdle(IoSession session, IdleStatus status)
				throws Exception {
			session.close(true);
		}

		@Override
		public void exceptionCaught(IoSession session, Throwable cause)
				throws Exception {
			log.warn("server出错", cause);
			super.exceptionCaught(session, cause);
			session.close(true);
		}
	}
}